# -*- coding: utf-8 -*-
import socket
import threading
import time


class SocketServer:
    """
    SOCKET 服务端
    """

    def __init__(self, host, port, handle_fun):
        """
        初始化 socket 服务端
        :param host:            socket绑定的ip
        :param port:            socket绑定的端口
        :param handle_fun:      处理客户端方法的方法名
        """
        self.client_sk = []
        self.socket = None
        self.host = host
        self.port = port
        self.handle_fun = handle_fun

    def start_server(self):
        """
        启动 TCP_SERVER 端服务
        :return:
        """
        try:
            # 1. 初始化服务端socket
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

            # 防止socket server重启后端口被占用（socket.error: [Errno 98] Address already in use）
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

            # 2. bind：将套接字与本地主机和端口绑定
            # host = socket.gethostname()        # 获取本地主机名称
            self.socket.bind((self.host, self.port))

            # 3. listen：设置监听最大连接数
            self.socket.listen(10)
        except socket.error as msg:
            print(msg)

        # 获取本地服务器的连接信息
        myaddr = self.socket.getsockname()
        print("启动——Socket服务，服务端地址:%s" % str(myaddr))

        while True:
            # 4. accept：获取一个客户端连接
            client_socket, addr = self.socket.accept()
            print("连接地址:%s" % str(addr))
            # 加入客户端集合
            self.client_sk.append(client_socket)
            try:
                # 5. 为每一个请求开启一个处理线程
                threading.Thread(target=self.handle_fun, args=(client_socket, addr,)).start()
            except ConnectionResetError:
                print("客户端 %s:%s异常断开连接" % addr)
                continue
            except KeyboardInterrupt:
                print("服务器关闭")
                break
        # 7. close
        self.socket.close()

    def close_socket(self):
        try:
            self.socket.close()
        except Exception as e:
            print(e)
            pass

    def broadcast_message(self, message):
        for client in self.client_sk:
            try:
                client.send(message.encode())
            except OSError:  # Client disconnected
                self.client_sk.remove(client)


class SocketClient:
    """
    socket客户端
    """

    def __init__(self, host, port, handle_fun, timeout=10, encoding='utf-8'):
        self.socket = None
        self.host = host
        self.port = port
        self.timeout = timeout
        self._encoding = encoding
        self.handle_fun = handle_fun

    def create_connect(self):
        """
        建立连接
        :return:
        """
        try:
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

            # 连接服务端
            self.socket.connect((self.host, self.port))

            # 设置超时响应
            self.socket.settimeout(self.timeout)

            # 5. 为每一个请求开启一个处理线程
            threading.Thread(target=self.handle_fun, args=(self.socket,)).start()
        except socket.error as e:
            print("TCP服务器连接异常,尝试重新连接 (5s) ...！, %s", e)
            self.socket.close()
            time.sleep(5)  # 断开连接后,每 5s 重新连接一次
            self.create_connect()

    def send_msg(self, msg):
        """
        客户端发送消息
        增加客户端断线重连机制
        :param msg:
        :return:
        """
        try:
            self.socket.send(msg.encode(self._encoding))
        except socket.error as e:
            print("TCP服务器连接异常,尝试重新连接 (5s) ...！, %s", e)

            # 重新建立连接
            self.create_connect()


if __name__ == '__main__':
    def func_hand(client, address):
        print(f"这里是处理函数.......... 客户端={address}")
        while True:
            try:
                data = client.recv(1024)
                if not data:
                    print("客户端%s:%s断开连接" % address)
                    break
                # client_socket.send(data)
                print("接收到来自%s:%s的消息:" % address)
                print(data.decode('utf-8'))
            except:
                print("客户端 %s:%s异常断开连接" % address)
                break


    print("socket_server............................")
    server = SocketServer("127.0.0.1", 8888, func_hand)
    server.start_server()

    print("server send msg.................................")
    while True:
        msg = input("发送消息给客户端")
        server.broadcast_message(msg.encode())
        time.sleep(2)
